package edu.usc.csci538.hw6.data;

import edu.usc.csci538.hw6.Utils;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;


public class CalendarEntryManager {
    private static final CalendarEntryManager singleton = new CalendarEntryManager();
    public static CalendarEntryManager get() {
        return singleton;
    }
    
    private Vector entries;  // of CalendarEntry
    protected CalendarEntryManager() {
        entries = new Vector();
    }
    
    public void addEntry(CalendarEntry entry) {
        entries.addElement(entry);
    }
    
    public void deleteEntry(CalendarEntry entry) {
        entries.removeElement(entry);
    }

    public Vector getEntriesForDate(Calendar date) {
        return getEntriesForDate(date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DATE));
    }

    void reset() {
        entries.removeAllElements();
    }
    
    private boolean eventMatchesTime(CalendarEntry event,
            int year, int month, int date, Integer hour, Integer min, Boolean isAM) {
        Calendar eventDate = Calendar.getInstance();
        Calendar targetDate = Calendar.getInstance();
        eventDate.setTime(new Date(0));
        targetDate.setTime(new Date(0));
        
        eventDate.set(Calendar.YEAR, event.getYear());
        eventDate.set(Calendar.MONTH, event.getMonth());
        eventDate.set(Calendar.DATE, event.getDate());
        if (hour != null && min != null && isAM != null) {
            eventDate.set(Calendar.HOUR, event.getStartTimeHour());
            eventDate.set(Calendar.MINUTE, event.getStartTimeMinute());
            eventDate.set(Calendar.AM_PM, event.isStartTimeAM()? Calendar.AM : Calendar.PM);
        }
        
        targetDate.set(Calendar.YEAR, year);
        targetDate.set(Calendar.MONTH, month);
        targetDate.set(Calendar.DATE, date);
        if (hour != null && min != null && isAM != null) {
            targetDate.set(Calendar.HOUR, hour.intValue());
            targetDate.set(Calendar.MINUTE, min.intValue());
            targetDate.set(Calendar.AM_PM, isAM.booleanValue()? Calendar.AM : Calendar.PM);
        }
        
        if (targetDate.getTime().getTime() < eventDate.getTime().getTime()) return false;
        if (event.getRepeat() == CalendarEntry.REPEAT_NONE) {
            return targetDate.getTime().getTime() == eventDate.getTime().getTime();
        }
        if (event.getRepeat() == CalendarEntry.REPEAT_MONTHLY) {
            targetDate.set(Calendar.YEAR, event.getYear());
            targetDate.set(Calendar.MONTH, event.getMonth());
            return targetDate.getTime().getTime() == eventDate.getTime().getTime();
        }
        int frequency = 0;
        int dayInSecs = 24*60*60;
        switch (event.getRepeat()) {
            case CalendarEntry.REPEAT_DAILY:
                frequency = dayInSecs;
                break;
            case CalendarEntry.REPEAT_WEEKLY:
                frequency = 7 * dayInSecs;
                break;
        }
        return (targetDate.getTime().getTime()/1000 - eventDate.getTime().getTime()/1000) % frequency == 0;
    }
    
    public Vector getEntriesForDate(int year, int month, int date) {
        Vector results = new Vector();
        for (int i=0; i < entries.size(); i++) {
            CalendarEntry entry = (CalendarEntry)entries.elementAt(i);
            if (eventMatchesTime(entry, year, month, date, null, null, null)) {
                results.addElement(entry);
            }
        }
        return sortResults(results);
    }
    
    private Vector sortResults(Vector /* of CalendarEntry*/ list) {
        // List is small, bubble sort
        for (int i=0; i < list.size(); i++) {
            for (int j=i+1; j < list.size(); j++) {
                CalendarEntry entryi = (CalendarEntry) list.elementAt(i);
                CalendarEntry entryj = (CalendarEntry) list.elementAt(j);
                if (Utils.timeAsInteger(entryi.getStartTimeHour(), entryi.getStartTimeMinute(), entryi.isStartTimeAM()) >
                    Utils.timeAsInteger(entryj.getStartTimeHour(), entryj.getStartTimeMinute(), entryj.isStartTimeAM())) {
                    // Swap i, j
                    list.setElementAt(entryi, j);
                    list.setElementAt(entryj, i);
                }
            }
        }
        return list;
    }
    
    public Vector getEntriesForDateAndTime(int year, int month, int date, int hour, int min, boolean isAM) {
        Vector results = new Vector();
        for (int i=0; i < entries.size(); i++) {
            CalendarEntry entry = (CalendarEntry)entries.elementAt(i);
            if (eventMatchesTime(entry, year, month, date, new Integer(hour), new Integer(min), new Boolean(isAM))) {
                results.addElement(entry);
            }
        }
        return results;
    }
}
